package ferp.core.tutorial;

import ferp.core.card.Card;
import ferp.core.game.Bid;
import ferp.core.game.Game;
import ferp.core.game.Settings;
import ferp.core.game.Trick;
import ferp.core.player.Player;
import ferp.core.tutorial.beginner.AllPass;
import ferp.core.tutorial.beginner.Misere;
import ferp.core.tutorial.beginner.Tricking;

import java.util.ArrayList;
import java.util.List;

/**
 * User: olegs
 * Date: 10/11/2014 09:22
 */
public abstract class Scenario
{
  public static final int NO_ID = -1;

  // multilingual strings
  public static final class Resource
  {
    public Resource() {}
    public Resource(String ru, String en) {set(ru, en);}

    public void set(String ru, String en)
    {
      this.ru = ru;
      this.en = en;
    }

    public String text(Settings.Locale locale)
    {
      switch (locale)
      {
        case RUSSIAN: return ru;
        case ENGLISH: return en;
        default: return null;
      }
    }

    private String ru;
    private String en;
  }

  public static final class Note
  {
    public enum Position {TOP, CENTER, BOTTOM}

    public static Note top(Resource resource) {return new Note(Position.TOP, resource);}
    public static Note center(Resource resource) {return new Note(Position.CENTER, resource);}
    public static Note bottom(Resource resource) {return new Note(Position.BOTTOM, resource);}

    public String text(Settings.Locale locale) {return resource.text(locale);}
    public Position position() {return position;}

    private Note(Position position, Resource resource)
    {
      this.position = position;
      this.resource = resource;
    }

    private final Position position;
    private Resource resource;
  }

  // 'set over' resources
  public static final class SetOver
  {
    public void bidding(Resource r) {bidding = new Note(Note.Position.CENTER, r);}
    public void contracting(Resource r) {contracting = new Note(Note.Position.CENTER, r);}
    public void moving(Resource r) {moving = new Note(Note.Position.CENTER, r);}

    private Note bidding;
    private Note contracting;
    private Note moving;
  }

  // bid and note for bidding and contracting modes
  public static final class BidData
  {
    public BidData(Bid bid, Note note)
    {
      this.bid = bid;
      this.note = note;
    }

    public Bid bid;
    public Note note;
  }

  // drop cards and note for dropping mode
  public static final class DropData
  {
    public int[] cards = new int[Game.TALON_SIZE];
    public Note note;
  }

  // trick and note for moving mode
  public static final class TrickData
  {
    public TrickData(int trick, Note note0, Note note1, Note note2) {this(trick, note0, note1, note2, null);}
    public TrickData(int trick, Note note0, Note note1, Note note2, Note over)
    {
      this.trick = trick;
      this.notes[0] = note0;
      this.notes[1] = note1;
      this.notes[2] = note2;
      this.over = over;
    }

    public TrickData(int trick, Resource r0, Resource r1, Resource r2) {this(trick, r0, r1, r2, null);}
    public TrickData(int trick, Resource r0, Resource r1, Resource r2, Resource over)
    {
      this(trick, r0 == null ? null : Note.top(r0), r1 == null ? null : Note.top(r1), r2 == null ? null : Note.top(r2), over != null ? Note.top(over) : null);
    }

    public int trick;
    public Note[] notes = new Note[Game.PLAYERS];
    public Note over;
  }

  public static Scenario get(int id) {return scenarios[id];}

  public static List<String> getNames(Settings.Locale locale)
  {
    List<String> names = new ArrayList<String>(scenarios.length);

    for (Scenario scenario : scenarios)
      names.add(scenario.name.text(locale));

    return names;
  }

  public Scenario(Resource name)
  {
    this.name = name;

    // common introduction
    introduction.add(new Resource("Перед Вами <b>объяснение</b> к уроку. Настоятельно рекомендуется прочитать его <b>до конца</b>. Кнопки внизу позволяют листать страницы. Для закрытия и перехода к началу урока коснитесь текста. Открыть объяснение повторно можно в любое время из <b>меню</b> приложения.",
                                  "This is an <b>explanation</b> to the lesson. It is highly recommended to read <b>all of it</b>. The buttons at the bottom are for switching pages. Tapping the text would close it and start the lesson. You can open the explanation at any time from the application's <b>menu</b>."));
    introduction.add(new Resource("В течение урока, на экране будут появляться <b>подсказки</b>, объясняющие ситуацию в игре, действия игроков либо призывающие <b>Вас</b> выполнить какие либо действия.",
                                  "During the lesson you will be presented with <b>hints</b> explaining game situation, player actions or asking <b>you</b> to perform certain actions."));
    introduction.add(new Resource("В <b>первых</b> 2-х случаях, нажатие на любое место на экране позволит продвинуться дальше. В <b>последнем</b> же случае следует выполнить указанное действие (ищите значок {mark} на игровом столе).",
                                  "In the <b>former</b> 2 cases tapping the screen would advance the lesson. In the <b>latter</b> case you must perform the required actions (look for the {mark} icon on the game table)."));
    introduction.add(new Resource("Если Вы заметили <font color=\"red\">ошибки</font> в тексте, <font color=\"yellow\">неточности</font> в уроках или хотели бы <font color=\"green\">предложить</font> более продвинутые темы - воспользуйтесь пунктом меню <b>Сообщить о проблеме</b>, оставив свой адрес для обратной связи.",
                                  "Should you notice any <font color=\"red\">errors</font> in the text, <font color=\"yellow\">discrepancies</font> in lessons or would like to <font color=\"green\">suggest</font> more advanced topics - please use <b>Report game</b> from the menu, specifying your e-mail address for further communication."));
  }

  // introduction
  public int pages() {return introduction.size();}
  public String getPageText(Settings.Locale locale, int page) {return introduction.get(page).text(locale);}

  // 'getters'
  public String name(Settings.Locale locale) {return name.text(locale);}
  public int dealer() {return dealer;}
  public int hand(int player) {return hands[player];}
  public int talon(int i) {return talon[i];}
  public Bid bid(int round, int player) {return bids[round][player].bid;}
  public int[] drop() {return drop.cards;}
  public Bid contract(int round, int player) {return contracts[round][player].bid;}
  public boolean stand() {return stand;}

  public Card card(int round, Player player)
  {
    // 'round' equals to tricks.length when opening initial position
    return round < tricks.length ? Trick.card(tricks[round].trick, player) : null;
  }

  // bidding notes
  public Note getBiddingOptionsNote(int round, int player) {return bids[round][player].note;}
  public Note getBiddingSetOverNote() {return setOver.bidding;}

  // dropping notes
  public Note getDroppingOptionsNote() {return drop.note;}

  // contracting notes
  public Note getContractingOptionsNote(int round, int player) {return contracts[round][player].note;}
  public Note getContractingSetOverNote() {return setOver.contracting;}

  // game type note
  public Note getGameTypeOptionsNote() {return gameType;}

  // moving notes
  public Note getMovingOptionsNote(int round, int player) {return tricks[round].notes[player];}
  public Note getMovingRoundOverNote(int round) {return tricks[round].over;}
  public Note getMovingSetOverNote() {return setOver.moving;}

  // scoring note
  public String getScoringText(Settings.Locale locale) {return scoring.text(locale);}

  // build methods
  protected void deal(int dealer, int hand0, int hand1, int hand2, int talon0, int talon1)
  {
    this.dealer = dealer;
    hands[0] = hand0;
    hands[1] = hand1;
    hands[2] = hand2;
    talon[0] = talon0;
    talon[1] = talon1;
  }

  protected void bid(int round, int player, Bid bid, Note note) {bids[round][player] = new BidData(bid, note);}

  protected void drop(int drop0, int drop1, Resource r)
  {
    drop.cards[0] = drop0;
    drop.cards[1] = drop1;

    if (r != null)
      drop.note = new Note(Note.Position.TOP, r);
  }

  protected void contract(int round, int player, Bid bid, Note note) {contracts[round][player] = new BidData(bid, note);}
  protected void gameType(Resource r) {gameType = Note.top(r);}
  protected void trick(int round, int trick, Note note0, Note note1, Note note2, Note over) {tricks[round] = new TrickData(trick, note0, note1, note2, over);}
  protected void trick(int round, int trick, Note note0, Note note1, Note note2) {tricks[round] = new TrickData(trick, note0, note1, note2);}
  protected void trick(int round, int trick, Resource r0, Resource r1, Resource r2, Resource over) {tricks[round] = new TrickData(trick, r0, r1, r2, over);}
  protected void trick(int round, int trick, Resource r0, Resource r1, Resource r2) {tricks[round] = new TrickData(trick, r0, r1, r2);}
  protected void trick(int round, int trick) {tricks[round] = new TrickData(trick, (Note)null, null, null);}
  protected void trick(int round, int trick, Resource over) {tricks[round] = new TrickData(trick, null, null, null, over);}
  protected void scoring(Resource scoring) {this.scoring = scoring;}

  // scenario name
  protected final Resource name;

  // introduction pages
  protected final ArrayList<Resource> introduction = new ArrayList<Resource>();

  // state
  protected int dealer;
  protected int[] hands = new int[Game.PLAYERS];
  protected int[] talon = new int[Game.TALON_SIZE];
  protected BidData[][] bids = new BidData[9][Game.PLAYERS];
  protected DropData drop = new DropData();
  protected BidData[][] contracts = new BidData[2][Game.PLAYERS];
  protected Note gameType;
  protected boolean stand;
  protected TrickData[] tricks = new TrickData[Game.MAXIMUM_ROUNDS];
  protected Resource scoring;

  // 'setOver' notes
  protected SetOver setOver = new SetOver();

  private static final Scenario[] scenarios = {
      new Tricking.Lesson1(),
      new Tricking.Lesson2(),
      new AllPass(),
      new Misere.Lesson1(),
      new Misere.Lesson2()
  };
}
